package com.xinziruo.crawl.domain.crawl;

import java.io.InputStream;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;

import com.xinziruo.crawl.domain.crawl.engine.ParamType;
import com.xinziruo.crawl.domain.crawl.expression.CrawlParseStringFilterConfig;
import com.xinziruo.crawl.infrastruture.util.ExceptionUtils;

/**
 * 
 * @author loudyn
 * 
 */
public class CrawlApiObjectFactory {

	private final static ObjectMapper MAPPER = new ObjectMapper();
	private static final Comparator<CrawlApiExpression> EXPRESSION_COMPARATOR = new Comparator<CrawlApiExpression>() {

		@Override
		public int compare(CrawlApiExpression o1, CrawlApiExpression o2) {
			return o1.getSort() - o2.getSort();
		}

	};

	private static final Comparator<CrawlApiParam> PARAM_COMPARATOR = new Comparator<CrawlApiParam>() {

		@Override
		public int compare(CrawlApiParam o1, CrawlApiParam o2) {
			return o1.getSort() - o2.getSort();
		}

	};

	public static CrawlApiObject create(String temp) {
		try {
			
			InputStream template = CrawlApiObjectFactory.class
					.getResourceAsStream(temp);
			JsonNode templateJson = MAPPER.readValue(template, JsonNode.class);

			CrawlApiObject api = new CrawlApiObject();
			api.setName(templateJson.path("name").getTextValue());
			api.setCallbackUrl(templateJson.path("callbackUrl").getTextValue());
			api.setFollowingItem(templateJson.path("followingItem")
					.getBooleanValue());
			api.setCronExpression(getCronExpression());
			api.setEnterUrl(templateJson.path("enterUrl").getTextValue());
			api.setItemsExpression(templateJson.path("itemsExpression")
					.getTextValue());
			api.setPayloadString(templateJson.path("payloadString")
					.getTextValue());
			api.setClassify(templateJson.path("classify").getTextValue());
			createExpressions(api, templateJson);
			createParams(api, templateJson);

			return api;

		} catch (Exception e) {
			throw ExceptionUtils.toUnchecked(e);
		}
	}

	private static void createExpressions(CrawlApiObject api,
			JsonNode templateJson) {
		for (JsonNode node : templateJson.path("parseExpressions")) {

			CrawlApiExpression expr = new CrawlApiExpression();

			expr.setName(node.path("name").getTextValue());
			expr.setSort(node.path("sort").getIntValue());
			expr.setDescr(node.path("descr").getTextValue());
			expr.setExpression(node.path("expression").getTextValue());
			expr.setResultType(node.path("resultType").getTextValue());

			for (JsonNode filterNode : node.path("stringFilterConfigs")) {

				CrawlParseStringFilterConfig config = new CrawlParseStringFilterConfig();

				config.setSort(filterNode.path("sort").getIntValue());
				config.setRegex(filterNode.path("regex").getTextValue());
				config.setReplacement(filterNode.path("replacement")
						.getTextValue());
				expr.addStringFilterConfig(config);
			}

			api.addParseExpression(expr);
		}

		Collections.sort(api.getParseExpressions(), EXPRESSION_COMPARATOR);
	}

	private static void createParams(CrawlApiObject api, JsonNode templateJson) {

		for (JsonNode node : templateJson.path("params")) {

			CrawlApiParam param = new CrawlApiParam();

			param.setAttack(node.path("attack").getBooleanValue());
			param.setEncode(node.path("encode").getTextValue());
			param.setName(node.path("name").getTextValue());
			param.setType(ParamType.valueOf(node.path("type").getTextValue()));
			param.setSort(node.path("sort").getIntValue());
			param.setValue(node.path("value").getTextValue());

			api.addParam(param);
		}

		Collections.sort(api.getParams(), PARAM_COMPARATOR);
	}
	 
	public  static String getCronExpression(){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, +10);
		return  calendar.get(Calendar.SECOND)+" "+calendar.get(Calendar.MINUTE)+" "+calendar.get(Calendar.HOUR_OF_DAY)+" ? * "+calendar.get(Calendar.DAY_OF_WEEK);
	}
}
